package com.ipan.builder.entity;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.List;

import com.ipan.builder.Builder;
import com.ipan.builder.BuilderCfg;
import com.ipan.builder.BuilderCfg.BuildCfg;
import com.ipan.builder.ext.entity.DefEntityCfg;
import com.ipan.builder.freemarker.FreemarkerManager;
import com.ipan.builder.ognl.ValueStack;
import com.ipan.builder.util.BdClassLoaderUtils;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * 实体类操作默认实现
 * 
 * 说明：
 * 1）.ftl模板可以通过OGNL访问BuilderCfg、BuildCfg、JpaEntityCfg对象以及公共变量、扩展变量；
 * 2）开发人员只要关心.ftl模板文件的编写即可；
 * 
 * @author iPan
 * @version 2013-12-6
 */
public class DefaultEntityOp implements EntityOp {

	protected ValueStack vs;
	protected String classpathToPath;

	public DefaultEntityOp(ValueStack vs) {
		this.vs = vs;
		this.classpathToPath = BuilderCfg.getInstance().getEntityClassPath().replace(".", "\\");
	}
	
	/**
	 * JpaEntityCfg + All BuildCfg
	 */
	public synchronized void buildCode(JpaEntityCfg entityCfg) {
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		List<BuildCfg> buildCfgList = BuilderCfg.getInstance().getBuildCfgList();
		clearVS();
		for (BuildCfg buildCfg : buildCfgList) {
			buildCode(config, entityCfg, buildCfg);
		}
	}
	
	/**
	 * JpaEntityCfg + BuildCfg
	 */
	public synchronized void buildCode(JpaEntityCfg entityCfg, BuildCfg buildCfg) {
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		clearVS();
		buildCode(config, entityCfg, buildCfg);
	}

	/**
	 * All JpaEntityCfg + All BuildCfg
	 */
	public synchronized void buildAllEntites() {
		clearVS();
		List<JpaEntityCfg> result = EntityOpUtils.loadJpaEntityCfgList();
		List<BuildCfg> buildCfgList = BuilderCfg.getInstance().getBuildCfgList();
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		for (JpaEntityCfg entityCfg : result) {
			for (BuildCfg buildCfg : buildCfgList) {
				buildCode(config, entityCfg, buildCfg);
			}
		}
	}

	/**
	 * All JpaEntityCfg + BuildCfg
	 */
	public synchronized void buildAllEntites(BuildCfg buildCfg) {
		clearVS();
		List<JpaEntityCfg> result = EntityOpUtils.loadJpaEntityCfgList();
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		for (JpaEntityCfg entityCfg : result) {
			buildCode(config, entityCfg, buildCfg);
		}
	}
	
	protected File getEntitiesDir() {
		File dir = null;
		String path = BuilderCfg.getInstance().getEntityClassPath();
		try {
			path = path.replace(".", "/");
			String absolutePath = BdClassLoaderUtils.getResource(path, DefaultEntityOp.class).getFile();
			dir = new File(absolutePath);
		} catch (Exception e) {
			throw new IllegalArgumentException("实体类所在classpath路径错误.", e);
		}
		return dir;
	}
	
	protected synchronized void buildCode(Configuration config, JpaEntityCfg entityCfg, BuildCfg buildCfg) {
		String[] files = buildCfg.getFiles();
		if (files == null || files.length < 1) {
			return ;
		}
		vs.push(buildCfg);
		vs.push(entityCfg);
		for (String fileName : files) {
			Template template = null;
			try {
				String relativePath = buildCfg.getRelativeTemplatePath(fileName);
				template = config.getTemplate(relativePath);
			} catch (IOException e2) {
				continue ;
			}
			
			File file = null;
			Writer writer = null;
			try {
				file = buildCfg.createFile(Builder.buildTemplateName(vs, fileName));
				writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), FreemarkerManager.DEFAULT_ENCODING));
				template.process(FreemarkerManager.createOgnlHashModel(vs), writer);
			} catch(Exception e) {
				throw new RuntimeException("生成代码出错.", e);
			} finally {
				if (writer != null) {
					try {
						writer.close();
					} catch (IOException e1) {
					}
				}
			}
		}
		vs.pop();
		vs.pop();
	}
	
	protected synchronized void buildCode(Configuration config, DefEntityCfg entityCfg, BuildCfg buildCfg) {
		String[] files = buildCfg.getFiles();
		if (files == null || files.length < 1) {
			return ;
		}
		vs.push(buildCfg);
		vs.push(entityCfg);
		for (String fileName : files) {
			Template template = null;
			try {
				String relativePath = buildCfg.getRelativeTemplatePath(fileName);
				template = config.getTemplate(relativePath);
			} catch (IOException e2) {
				continue ;
			}
			
			File file = null;
			Writer writer = null;
			try {
				file = buildCfg.createFile(Builder.buildTemplateName(vs, fileName));
				writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), FreemarkerManager.DEFAULT_ENCODING));
				template.process(FreemarkerManager.createOgnlHashModel(vs), writer);
			} catch(Exception e) {
				throw new RuntimeException("生成代码出错.", e);
			} finally {
				if (writer != null) {
					try {
						writer.close();
					} catch (IOException e1) {
					}
				}
			}
		}
		vs.pop();
		vs.pop();
	}

	/**
	 * 除去所有JpaEntityCfg对象.
	 */
	protected void clearVS() {
		while (vs.size() > 0 && vs.peek() instanceof JpaEntityCfg) {
			vs.pop();
		}
	}

	@Override
	public synchronized void buildCode(DefEntityCfg entityCfg) {
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		List<BuildCfg> buildCfgList = BuilderCfg.getInstance().getBuildCfgList();
		clearVS();
		for (BuildCfg buildCfg : buildCfgList) {
			buildCode(config, entityCfg, buildCfg);
		}
	}

	@Override
	public synchronized void buildCode(DefEntityCfg entityCfg, BuildCfg buildCfg) {
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		clearVS();
		buildCode(config, entityCfg, buildCfg);
	}

	@Override
	public void buildAllDefEntites() {
		clearVS();
		List<DefEntityCfg> result = EntityOpUtils.loadDefEntityCfgList();
		List<BuildCfg> buildCfgList = BuilderCfg.getInstance().getBuildCfgList();
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		for (DefEntityCfg entityCfg : result) {
			for (BuildCfg buildCfg : buildCfgList) {
				buildCode(config, entityCfg, buildCfg);
			}
		}
	}

	@Override
	public void buildAllDefEntites(BuildCfg buildCfg) {
		clearVS();
		List<DefEntityCfg> result = EntityOpUtils.loadDefEntityCfgList();
		Configuration config = FreemarkerManager.getDefaultConfiguration();
		for (DefEntityCfg entityCfg : result) {
			buildCode(config, entityCfg, buildCfg);
		}
	}
	
}
